package com.yilin.tms.core.components.interceptor;

import com.google.gson.reflect.TypeToken;
import com.yilin.commons.util.ArrayUtil;
import com.yilin.commons.util.DateTimeUtil;
import com.yilin.commons.util.JsonUtil;
import com.yilin.tms.core.application.AppUtil;
import com.yilin.tms.core.commons.constant.HttpConstant;
import com.yilin.tms.core.commons.base.BaseCode;
import com.yilin.tms.core.commons.annotation.AbnormalVerify;
import com.yilin.tms.core.commons.annotation.SkipGateway;
import com.yilin.tms.core.components.redis.RedisClient;
import com.yilin.tms.core.components.redis.RedisKeys;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.MethodParameter;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ReqHttpInterceptor extends HandlerInterceptorAdapter {

    private Logger logger = LoggerFactory.getLogger(ReqHttpInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        if (!(handler instanceof HandlerMethod)) return responseErr(response, BaseCode.RES_NOT_EXIST, "请求的链接地址不存在");
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        String customerIp = AppUtil.getIp(request);
        RedisClient redisClient = RedisClient.getInstance();
        int violationCount = 1;

        //#### 前置人机校验
        String mobile = request.getHeader(HttpConstant.MOBILE);
        String YES = redisClient.hget(RedisKeys.HTTP_MAN_MACHINE_KEY, customerIp);
//        if (YES != null && YES.equals("YES") && mobile==null) return responseErr(response, BaseCode.SAFE_MAN_MACHINE, "请先滑动滑块完成验证");

        //#### 进行本地服务拦截监控 测试专用
        SkipGateway skipGateway = handlerMethod.getMethodAnnotation(SkipGateway.class);
        if (skipGateway == null && (request.getHeader(HttpConstant.GATEWAY_ZUUL) == null)) {
            String countTx = redisClient.hget(RedisKeys.HTTP_VIOLATION_KEY, customerIp);
            if (AppUtil.isNumeric(countTx)) violationCount += Integer.parseInt(countTx);
            redisClient.hset(RedisKeys.HTTP_VIOLATION_KEY, customerIp, String.valueOf(violationCount));
            redisClient.expire(RedisKeys.HTTP_VIOLATION_KEY, 60 * 60 * 24);//24小时自动清除
            String sysWarning = "⚠⚠⚠⚠警告！客户[IP：%s]进行了%s次违规请求，请求方法：%s，请对该用户进行后续访问监控！";
            logger.warn(String.format(sysWarning, customerIp, violationCount, handlerMethod.getMethod().getName()));
            String retInfo = "您的请求已被拦截，请按照API规定进行请求，多次违规请求，可能会被系统录入黑名单！";
            return responseErr(response, BaseCode.FAIL_CODE, retInfo);
        }

        //#### 前台变态请求，连续请求拦截
        AbnormalVerify abnormalVerify = handlerMethod.getMethodAnnotation(AbnormalVerify.class);
        if (abnormalVerify != null && mobile==null) {
            int page = checkPage(handlerMethod, request);
            int maxCount = abnormalVerify.maxCount(), timer = abnormalVerify.timer();
            String field = String.format("%s_page%s", customerIp, page);
            //获取该IP在timer内的请求次数，注意：分页切换时不验证
            String hget = redisClient.hget(RedisKeys.HTTP_ABNORMAL_KEY, field);
            if (hget == null) hget = "{\"lastTime\":"+System.currentTimeMillis()+",\"lastCount\":0}";
            Map<String, Object> map = JsonUtil.jsonToObject(hget, new TypeToken<Map<String, Object>>() {});
            long lastTime = Long.parseLong(map.get("lastTime").toString()), lastCount =Long.parseLong(map.get("lastCount").toString());
            if (DateTimeUtil.secondBetween(lastTime, System.currentTimeMillis()) < timer) lastCount++;
            else lastCount = 0;
//            if (lastCount > maxCount) {
//                redisClient.hset(RedisKeys.HTTP_MAN_MACHINE_KEY, customerIp, "YES");
//                redisClient.hdel(RedisKeys.HTTP_ABNORMAL_KEY, field);
//                return responseErr(response, BaseCode.SAFE_MAN_MACHINE, "请先滑动滑块完成验证");
//            }
            map.put("lastCount", lastCount);
            map.put("lastTime", System.currentTimeMillis());
            redisClient.hset(RedisKeys.HTTP_ABNORMAL_KEY, field, JsonUtil.objectToJson(map));
        }
        return true;
    }


    //返回前台数据
    private boolean responseErr(HttpServletResponse response, Integer code, String msg) {
        try {
            Map<String, Object> returnData = new HashMap<>();
            response.setCharacterEncoding("UTF-8");//设置字符集为'UTF-8'
            response.setContentType("application/json");//设置格式为text/json 
            returnData.put(HttpConstant.SUCCESS, false);
            returnData.put(HttpConstant.MSG, msg);
            returnData.put(HttpConstant.CODE, code);
            PrintWriter write = response.getWriter();
            write.write(JsonUtil.objectToJson(returnData));
            write.flush();
            write.close();
            return false;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }


    // 返回类型名称列表
    private int checkPage(HandlerMethod handlerMethod, HttpServletRequest request) {
        MethodParameter[] methodParameters = handlerMethod.getMethodParameters();
        List<MethodParameter> pageList = ArrayUtil.whereBy(ArrayUtil.initList(methodParameters), obj -> {
            if (obj.getParameterName() == null) return false;
            return obj.getParameterName().equals("page");
        });
        if (pageList.size() == 0) return 0;
        String parameter = request.getParameter(ArrayUtil.first(pageList).getParameterName());
        return Integer.parseInt(parameter);
    }

}
